package com.gome.ocean.guava;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

public class ListenableFutureDemo {

    private static ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));

    private static ExecutorService          executorService          = Executors.newFixedThreadPool(10);

    public static void synchronous() {
        final long start = System.currentTimeMillis();
        Future<Object> future1 = executorService.submit(new Task1());
        Future<Object> future2 = executorService.submit(new Task2());
        Future<Object> future3 = executorService.submit(new Task3());

        try {
            Object result2 = future2.get();
            Object result1 = future1.get();
            Object result3 = future3.get();
            System.out.println(result1 + " " + result2 + " " + result3);
            System.out.println("synchronous:" + (System.currentTimeMillis() - start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    public static void parallel() throws InterruptedException {
        final long start = System.currentTimeMillis();
        ListenableFuture<Object> listenableFuture1 = listeningExecutorService.submit(new Task1());
        ListenableFuture<Object> listenableFuture2 = listeningExecutorService.submit(new Task2());
        ListenableFuture<Object> listenableFuture3 = listeningExecutorService.submit(new Task3());

        ListenableFuture<List<Object>> successfulQueries = Futures.successfulAsList(listenableFuture1,
            listenableFuture2,
            listenableFuture3);
        
        Futures.addCallback(successfulQueries, new FutureCallback<Object>() {

            public void onFailure(Throwable arg0) {
                System.out.println(arg0);
            }

            public void onSuccess(Object arg0) {
                System.out.println(arg0);
                System.out.println("parallel:" + (System.currentTimeMillis() - start));
            }
        });
        
        while(true){
            System.out.println("aaaaa");
            Thread.sleep(1000);
        }
        
    }

    public static void main(String[] args) throws InterruptedException {
        synchronous();
        parallel();
        shutdown();
    }

    public static void shutdown() {
        listeningExecutorService.shutdown();
        executorService.shutdown();
    }

    public static class Task1 implements Callable<Object> {

        public Object call() throws Exception {
            Thread.sleep(5000);
            return "Task1";
        }
    }

    public static class Task2 implements Callable<Object> {

        public Object call() throws Exception {
            Thread.sleep(3000);
            return "Task2";
        }
    }

    public static class Task3 implements Callable<Object> {

        public Object call() throws Exception {
            Thread.sleep(4000);
            return "Task3";
        }
    }
}
